package com.czk.stack.arithmeticExpressionPractice;

/**
 * 数学运算的练习
 *
 * @Author:ChenZhangKun
 * @Date: 2021/5/27 10:14
 */
public class ArithmeticExpressionPractice {
    public static void main(String[] args) {
        String str="30+2*6-2";
        int calculate = calculate(str);
        System.out.println(calculate);
    }

    public static int calculate(String s) {
        // 是否为空
        if (s == null) throw new NullPointerException("s不能为空");
        // 定义扫描的长度
        int index = 0;
        // 定义扫描到的字符
        char c = ' ';
        // 定义拼接的数字
        String keepNum = "";
        // 定义数字栈
        MyStack numStack = new MyStack(10);
        // 定义符号栈
        MyStack operatorStack = new MyStack(5);
        // 循环
        while (true) {
            // 拿到第字符
            c = s.substring(index, index + 1).charAt(0);
            // 是否是操作符
            if (operatorStack.isOperator(c)) {
                // 操作符号栈是否为空
                if (operatorStack.isEmpty()) {
                    // 直接放入符号栈
                    operatorStack.push(c);
                } else {
                    // 比较优先级
                    // 拿到符号栈的符号优先级
                    int peek = operatorStack.peek();
                    int priority = operatorStack.priority(peek);
                    // 当前符号的优先级
                    int priority1 = operatorStack.priority(c);
                    // 比较优先级大小
                    if (priority1 > priority) {
                        // 优先级大于栈中的优先级
                        // 入栈
                        operatorStack.push(c);
                    } else {
                        // 小于栈中元素的优先级
                        // 计算栈中的元素
                        int num1 = numStack.pop();
                        int num2 = numStack.pop();
                        int pop = operatorStack.pop();
                        // 计算
                        int cal = numStack.cal(num1, num2, pop);
                        // 压回数字栈顶
                        numStack.push(cal);
                    }
                }
            } else {
                // 是否是多位数
                keepNum += c;
                // 是否是最后一位
                if (index == s.length() - 1) {
                    // 直接入站
                    numStack.push(Integer.parseInt(keepNum));
                } else {
                    // 下一位是否是数字
                    if (operatorStack.isOperator(s.substring(index +1, index + 2).charAt(0))) {
                        // 是操作符，直接入站
                        numStack.push(Integer.parseInt(keepNum));
                        // 情况keepNum
                        keepNum = "";
                    }
                }
            }
            // 是否是最后一位
            // 扫描长度加一

            index++;
            if (index >= s.length() - 1) {
                // 直接返回
                break;
            }
        }
        int num1 = 0;
        int num2 = 0;
        ;
        int oper = 0;
        while (true) {
            // 计算剩余
            if (operatorStack.isEmpty()) {
                break;
            }
            // 弹栈
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operatorStack.pop();
            int cal = numStack.cal(num1, num2, oper);
            numStack.push(cal);
        }
        // 返回值
        return numStack.pop();
    }
}

class MyStack {
    // 栈大小
    private int maxSize;
    // 存储栈元素的数组
    private int[] stack;
    // 栈顶元素
    // 初始化微-1
    private int top = -1;

    public MyStack(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[maxSize];
    }

    /**
     * 是否满了
     *
     * @return
     */
    public boolean isFull() {
        return stack.length == maxSize - 1;
    }

    /**
     * 是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return top == -1;
    }

    /**
     * 放入值
     *
     * @param value
     */
    public void push(int value) {
        if (isFull()) {
            throw new RuntimeException("栈满了，无法存放");
        }
        stack[++top] = value;
    }

    /**
     * 弹出栈
     *
     * @return
     */
    public int pop() {
        // 栈是否为空
        if (isEmpty()) {
            throw new RuntimeException("栈为空，无法弹出");
        }
        int value = stack[top];
        top--;
        return value;
    }

    /**
     * 查看栈顶元素
     *
     * @return
     */
    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("栈为空，无法弹出");
        }
        return stack[top];
    }

    /**
     * 遍历栈
     */
    public void list() {
        for (int i : stack) {
            System.out.println(i);
        }
    }

    /**
     * 符号优先级
     *
     * @param oper
     * @return
     */
    public int priority(int oper) {
        if (oper == '/' || oper == '*') {
            return 1;
        }
        if (oper == '+' || oper == '-') {
            return 0;
        }
        throw new RuntimeException("符号类型错误");
    }

    /**
     * 判断字符是否是运算符
     *
     * @param oper
     * @return
     */
    public boolean isOperator(char oper) {
        return oper == '/' || oper == '*' || oper == '+' || oper == '-';
    }

    // 计算方法
    public int cal(int num1, int num2, int oper) {
        int res = 0;
        switch (oper) {
            case '+':
                res = num2 + num1;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num2 * num1;
                break;
            case '/':
                res = num2 / num1;
                break;

        }
        return res;
    }
}